package com.kusen.proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

import static com.kusen.proxy.SuperMan.ProxyFactory.getProxyInstance;

interface Human {
    void eat();

    String say(String mes);
}

/**
 * 被代理类
 */
class SuperMan implements Human {

    @Override
    public void eat() {
        System.out.println("我在吃东西");
    }

    @Override
    public String say(String mes) {
        String hai = "我是" + mes;
        return hai;
    }


    /**
     * 实现动态代理，需要解决的问题
     * 问题一：如何根据加载到内存中的被代理类动态的创建一个代理类
     * 问题二：代理类如果感知到需要调用的方法
     */
    //生成代理类的工厂
    static class ProxyFactory {
        //调用此方法，放回一个代理类的对象。解决问题一
        public static Object getProxyInstance(Object obj) {
            MyInvocationHandler handler = new MyInvocationHandler();
            handler.bind(obj);//传入被代理类的对象，获取到被执行的方法
            return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), handler);

        }

    }

    static class MyInvocationHandler implements InvocationHandler {
        //这是一个被代理对象的实例
        private Object obj;

        public void bind(Object obj) {
            this.obj = obj;
        }

        /**
         * 解决问题二：在被代理类调用方法时 代理类也需要同时的调用这个方法使得代理类有被代理类的相同的功能
         *
         * @param proxy
         * @param method
         * @param args
         * @return
         * @throws Throwable
         */
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            Object invoke = method.invoke(obj, args);
            //返回代理类的对象
            return invoke;
        }
    }

    public static class ProxyText {
        public static void main(String[] args) {
            SuperMan superMan = new SuperMan();
            //放回共同的实现的接口
            Human human = (Human) ProxyFactory.getProxyInstance(superMan);
            human.eat();
            System.out.println(human.say("超人"));
            System.out.println(Math.round(-1.8));
            String str = "i";
            String str1 = new String("i");
            System.out.println(str.equals(str1));
        }
    }

}